#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include "wmark_dev.h"
#include <linux/dma-buf.h>
#include <linux/ion.h>
#include <linux/msm_ion.h>
#include <linux/list.h>
#include <linux/mutex.h>

#undef PDEBUG /* undef it, just in case */
#ifdef WMARK_DEBUG
#ifdef __KERNEL__
#define PDEBUG(fmt, args...) printk(KERN_DEBUG "DEMO: " fmt, ##args)
#else //usr space
#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args)
#endif
#else
#define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif

#undef PDEBUGG
#define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */

#define debug(fmt, arg...)                                                     \
	printk(KERN_DEBUG "%s %d " fmt "\n", __func__, __LINE__, ##arg)

#define error(fmt, arg...)                                                     \
	printk(KERN_ERR "%s %d " fmt "\n", __func__, __LINE__, ##arg)

#define info_log(fmt, arg...) printk("%s %d " fmt "\n", __func__, __LINE__, ##arg)

#define WMARK_DEV_NAME "wmark_dev_lookback"

static struct miscdevice wmark_dev;

typedef struct {
	wmark_buf_t data;
	struct list_head list;
} buf_list_t;

typedef struct {
	int index;
	unsigned long dma_buf_len;
	struct dma_buf *buf_p; // 保存 dma_buf 指针
} dma_info_buf_t;

typedef enum {
	APP_WRITE, // export 侧
	APP_READ,  // import 侧
} app_type_enum;

typedef struct {
	app_type_enum type;
} app_private_t;

typedef struct {
	struct mutex state_m_mutex;
	state_type_enum s_m_export;
	state_type_enum s_m_import;
} state_machine_t;

typedef struct {
	struct mutex mutex;
	control_msg_t msg;
	struct list_head list;
} control_msg_list_t;

typedef struct {
	struct mutex mutex;
	buf_list_t wmark_r_list_head;
	buf_list_t wmark_w_list_head;
	control_msg_list_t control_export_list_head;
	control_msg_list_t control_import_list_head;
	wait_queue_head_t r_wait; //等待队列的头
	wait_queue_head_t w_wait; //等待队列的头
	wait_queue_head_t export_msg_wait; //等待队列的头
	wait_queue_head_t import_msg_wait; //等待队列的头
	dma_info_buf_t dmabufs[DMA_BUFS_MAX_NUM];
	init_wmark_bufs_t wmark_buf_info;
	state_machine_t state_machine; // 状态机
} wmark_dev_bufs_manager_t;

wmark_dev_bufs_manager_t global_bufs_manager;

//函数申明
ssize_t wmark_read(struct file *filp, char __user *buf, size_t count,
		   loff_t *f_pos);
ssize_t wmark_write(struct file *filp, const char __user *buf, size_t count,
		    loff_t *f_pos);
loff_t wmark_llseek(struct file *filp, loff_t off, int whence);
long wmark_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
int clear_wmark_list(wmark_dev_bufs_manager_t *dev, struct list_head *list_head);

// 入
int push_msg(control_msg_list_t *new, struct list_head *head)
{
	control_msg_list_t *msg_list_head = container_of(head, control_msg_list_t, list);
	struct mutex *mutex = &msg_list_head->mutex;

	if (!new || !head) {
		error("fail");
		return -1;
	}

	mutex_lock(mutex);

	list_add(&new->list, head);

	mutex_unlock(mutex);

	return 0;
}

// 出
control_msg_list_t *pop_msg(struct list_head *head)
{
	control_msg_list_t *msg_list_head = container_of(head, control_msg_list_t, list);
	struct mutex *mutex = &msg_list_head->mutex;

	control_msg_list_t *ret = NULL;

	if (!head) {
		error("fail");
		return ret;
	}

	if (list_empty(head)) {
		return NULL;
	}

	mutex_lock(mutex);

	ret = list_first_entry(head, control_msg_list_t, list);
	list_del(head->next);

	mutex_unlock(mutex);

	return ret;
}

int send_msg_to_export(control_msg_t msg)
{
	wmark_dev_bufs_manager_t *dev = &global_bufs_manager;
	control_msg_list_t *_msg = NULL;

	_msg = kzalloc(sizeof(*_msg), GFP_KERNEL);
	if (!_msg) {
		error("_msg = NULL\n");
		return -1;
	}
	_msg->msg = msg;
	INIT_LIST_HEAD(&_msg->list);

	push_msg(_msg, &global_bufs_manager.control_export_list_head.list);
	wake_up_interruptible(&dev->export_msg_wait); // 通知 export 有消息
	debug("msg.state=%d", msg.state);

	return 0;
}

int send_msg_to_import(control_msg_t msg)
{
	wmark_dev_bufs_manager_t *dev = &global_bufs_manager;
	control_msg_list_t *_msg = NULL;

	_msg = kzalloc(sizeof(*_msg), GFP_KERNEL);
	if (!_msg) {
		error("_msg = NULL\n");
		return -1;
	}
	_msg->msg = msg;
	INIT_LIST_HEAD(&_msg->list);

	push_msg(_msg, &global_bufs_manager.control_import_list_head.list);
	wake_up_interruptible(&dev->import_msg_wait); // 通知 export 有消息
	debug("msg.state=%d", msg.state);

	return 0;
}

int clear_msg_list(struct list_head *list_head)
{
	control_msg_list_t *_buf = NULL;
	debug();

	do {
		_buf = pop_msg(list_head);
		if (_buf) {
			kfree(_buf);
		}
	} while(_buf);

	return 0;
}

void set_export_s_m(state_type_enum state)
{
	struct mutex *mutex = &global_bufs_manager.state_machine.state_m_mutex;

	mutex_lock(mutex);

	global_bufs_manager.state_machine.s_m_export = state;

	mutex_unlock(mutex);

}

void set_import_s_m(state_type_enum state)
{
	struct mutex *mutex = &global_bufs_manager.state_machine.state_m_mutex;

	mutex_lock(mutex);

	global_bufs_manager.state_machine.s_m_import = state;

	mutex_unlock(mutex);

}

state_type_enum get_export_s_m()
{
	struct mutex *mutex = &global_bufs_manager.state_machine.state_m_mutex;
	state_type_enum state;

	mutex_lock(mutex);

	state = global_bufs_manager.state_machine.s_m_export;

	mutex_unlock(mutex);

	return state;
}

state_type_enum get_import_s_m()
{
	struct mutex *mutex = &global_bufs_manager.state_machine.state_m_mutex;
	state_type_enum state;

	mutex_lock(mutex);

	state = global_bufs_manager.state_machine.s_m_import;

	mutex_unlock(mutex);

	return state;
}

int is_export_app(struct file *filp) {
	app_private_t *app = filp->private_data;

	if (!app) {
		error("app == NULL fail\n");
		return -1;
	}

	if (app->type == APP_WRITE) {
		return 1;
	} else if (app->type == APP_READ) {
		return 0;
	}

	error("app type fail\n");
	return -1;
}

int wmark_open(struct inode *inode, struct file *filp)
{
	app_private_t *app_data = NULL;

	app_data = (app_private_t *)kzalloc(sizeof(*app_data), GFP_KERNEL);
	if (!app_data) {
		error("kzalloc app_private data fail\n");
		goto error_alloc;
	}

	if ((filp->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
		// export open
		app_data->type = APP_WRITE;
		set_export_s_m(S_M_OPEN_EX);
	} else {
		// import open
		app_data->type = APP_READ;
		set_import_s_m(S_M_OPEN_IM);
	}

	filp->private_data = app_data;

	return 0;

error_alloc:
	return -1;
}

int wmark_release(struct inode *inode, struct file *filp)
{
	//wmark_inc--;
	control_msg_t msg;
	int i = 0;
	debug();
	for(i = 0; i < DMA_BUFS_MAX_NUM; i++) {
		global_bufs_manager.dmabufs[i].buf_p = NULL;
		global_bufs_manager.dmabufs[i].dma_buf_len = -1;
		global_bufs_manager.dmabufs[i].index = -1;
	}

	clear_wmark_list( &global_bufs_manager, &global_bufs_manager.wmark_w_list_head.list);
	clear_wmark_list( &global_bufs_manager, &global_bufs_manager.wmark_r_list_head.list);

	if (is_export_app(filp) > 0) {
		set_export_s_m(S_M_CLOSE_EX);

		msg.state = S_M_CLOSE_EX;
		send_msg_to_import(msg);

		clear_msg_list(&global_bufs_manager.control_export_list_head.list);
	} else {
		set_import_s_m(S_M_CLOSE_IM);

		msg.state = S_M_CLOSE_IM;
		send_msg_to_export(msg);
		clear_msg_list(&global_bufs_manager.control_import_list_head.list);
	}
	return 0;
}

void print_list_info(struct list_head *head)
{
	struct list_head *item;
	buf_list_t *buf_node = NULL;

	list_for_each(item, head) {
		buf_node = list_entry(item, buf_list_t, list);
		debug("                            buf_node.index=%d\n", buf_node->data.index);
	}
}

// 入
int push_wmark(buf_list_t *new, struct list_head *head)
{
	if (!new || !head) {
		error("fail");
		return -1;
	}
	list_add(&new->list, head);

	return 0;
}

// 出
buf_list_t *pop_wmark(struct list_head *head)
{
	buf_list_t *ret = NULL;
	// struct list_head *tmp_node = NULL;

	if (!head) {
		error("fail");
		return ret;
	}

	if (list_empty(head)) {
		return NULL;
	}

#if 0
	list_for_each(tmp_node, head) {
		break;
	}

	if (tmp_node) {
		ret = container_of(tmp_node, buf_list_t, list);
		list_del(tmp_node);
	}
#else
	ret = list_first_entry(head, buf_list_t, list);
	list_del(head->next);
#endif

	return ret;
}

int export_set_use_buf_index(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	buf_list_t *_new = NULL;
	wmark_buf_t kernel_recv;
	debug();

	mutex_lock(&dev->mutex);
	_new = (buf_list_t *)kmalloc(sizeof(buf_list_t), GFP_KERNEL);
	if (!_new) {
		error("fail");
		mutex_unlock(&dev->mutex);
		return -1;
	}
	INIT_LIST_HEAD(&_new->list);
	copy_from_user((void *)&kernel_recv, (void __user *)argp,
		       sizeof(kernel_recv));
	memcpy(&_new->data, &kernel_recv, sizeof(kernel_recv));
	debug("push_wmark -- index=%d", kernel_recv.index);
	push_wmark(_new, &dev->wmark_r_list_head.list); // 加入可读的 列表里，
	print_list_info(&dev->wmark_r_list_head.list);

	wake_up_interruptible(&dev->r_wait); // 通知 import 读

	mutex_unlock(&dev->mutex);

	return 0;
}

int export_get_free_buf_index(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	wmark_buf_t kernel_send;
	buf_list_t *_buf;
	debug();

	mutex_lock(&dev->mutex);

	_buf = pop_wmark(
		&dev->wmark_w_list_head.list); // 从 写 队列中拿 一个 free 的buf
	if (!_buf) {
		debug("pop_wmark == NULL");
		mutex_unlock(&dev->mutex);
		return -EAGAIN;
	}
	print_list_info(&dev->wmark_w_list_head.list);

	memcpy(&kernel_send, &_buf->data, sizeof(kernel_send));
	debug("pop_wmark -- index=%d", kernel_send.index);
	kfree(_buf);

	copy_to_user((void __user *)argp, (void *)&kernel_send,
		     sizeof(kernel_send));
	mutex_unlock(&dev->mutex);

	return 0;
}

int clear_wmark_list(wmark_dev_bufs_manager_t *dev, struct list_head *list_head)
{
	buf_list_t *_buf = NULL;
	debug();

	mutex_lock(&dev->mutex);
	do {
		_buf = pop_wmark(list_head);
		if (_buf) {
			kfree(_buf);
		}
	} while(_buf);
	mutex_unlock(&dev->mutex);

	return 0;
}

int import_set_free_buf_index(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	buf_list_t *_new = NULL;
	wmark_buf_t kernel_recv;
	debug();

	mutex_lock(&dev->mutex);
	_new = (buf_list_t *)kmalloc(sizeof(buf_list_t), GFP_KERNEL);
	if (!_new) {
		error("fail");
		mutex_unlock(&dev->mutex);
		return -1;
	}
	INIT_LIST_HEAD(&_new->list);
	copy_from_user((void *)&kernel_recv, (void __user *)argp,
		       sizeof(kernel_recv));

	memcpy(&_new->data, &kernel_recv, sizeof(kernel_recv));
	debug("push_wmark -- index=%d", kernel_recv.index);
	push_wmark(_new, &dev->wmark_w_list_head.list); // 加入可写的 列表里，
	print_list_info(&dev->wmark_w_list_head.list);

	wake_up_interruptible(&dev->w_wait); // 通知 exprot 可以写

	mutex_unlock(&dev->mutex);

	return 0;
}

int import_get_use_buf_index(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	wmark_buf_t kernel_send;
	buf_list_t *_buf;
	debug();

	mutex_lock(&dev->mutex);

	_buf = pop_wmark(
		&dev->wmark_r_list_head.list); // 从 写 队列中拿 一个 free 的buf
	if (!_buf) {
		debug("pop_wmark == NULL");
		mutex_unlock(&dev->mutex);
		return -EAGAIN;
	}
	print_list_info(&dev->wmark_r_list_head.list);
	memcpy(&kernel_send, &_buf->data, sizeof(kernel_send));
	debug("pop_wmark -- index=%d", kernel_send.index);

	kfree(_buf);

	copy_to_user((void __user *)argp, (void *)&kernel_send,
		     sizeof(kernel_send));
	mutex_unlock(&dev->mutex);

	return 0;
}

int export_init_dma_bufs(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	init_dma_bufs_t kernel_buf;
	int dma_buf_num = -1, i = -1, fd = -1, index = -1;

	copy_from_user((void *)&kernel_buf, (void __user *)argp,
		       sizeof(kernel_buf));

	dma_buf_num = kernel_buf.dma_buf_num;
	if (dma_buf_num > DMA_BUFS_MAX_NUM || dma_buf_num < 0) {
		error("input arg: dma_buf_num = %d error!", dma_buf_num);
		return -1;
	}

	for (i = 0; i < dma_buf_num; i++) {
		index = kernel_buf.dma_fds[i].index;
		if (index >= DMA_BUFS_MAX_NUM || index < 0) {
			error("input arg: index = %d error!", index);
			return -1;
		}

		fd = kernel_buf.dma_fds[i].fd;
		dev->dmabufs[index].buf_p = dma_buf_get(fd);
		dev->dmabufs[index].index = index;
		dev->dmabufs[index].dma_buf_len = kernel_buf.dma_fds[i].buf_len;
		debug("init dma-buf=%p fd=%d len=%d", dev->dmabufs[index].buf_p,
		      fd, dev->dmabufs[index].dma_buf_len);
	}

	return 0;
}

int import_init_dma_bufs(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	init_dma_bufs_t kernel_buf;
	int i = -1, fd = -1;

	for (i = 0; i < DMA_BUFS_MAX_NUM; i++) {
		if (!dev->dmabufs[i].buf_p) {
			error("dev->dmabufs[%d].buf_p == NULL fail!", i);
			return -EFAULT;
		}

		fd = dma_buf_fd(dev->dmabufs[i].buf_p, O_CLOEXEC);
		if (fd < 0) {
			error("get fd=%d dma_buf fail\n", fd);
			return -EINVAL;
		}
		kernel_buf.dma_fds[i].fd = fd;
		kernel_buf.dma_fds[i].index = dev->dmabufs[i].index;
		kernel_buf.dma_fds[i].buf_len = dev->dmabufs[i].dma_buf_len;
		debug("get : dma-buf=%p fd=%d len=%d", dev->dmabufs[i].buf_p, fd, kernel_buf.dma_fds[i].buf_len);
	}

	kernel_buf.dma_buf_num = i;
	debug("kernel dma_buf_num = %d", kernel_buf.dma_buf_num);
	copy_to_user((void __user *)argp, (void *)&kernel_buf,
		     sizeof(kernel_buf));
	return 0;
}

int export_init_wmark_bufs(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	init_wmark_bufs_t kernel_buf;

	copy_from_user((void *)&kernel_buf, (void __user *)argp,
		       sizeof(kernel_buf));
	dev->wmark_buf_info.num = kernel_buf.num;
	dev->wmark_buf_info.len = kernel_buf.len;
	debug("wmark_buf num=%d len=%d", dev->wmark_buf_info.num, dev->wmark_buf_info.len);

	return 0;
}

int import_init_wmark_bufs(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	init_wmark_bufs_t kernel_buf;

	kernel_buf.num = dev->wmark_buf_info.num;
	kernel_buf.len = dev->wmark_buf_info.len;
	copy_to_user((void __user *)argp, (void *)&kernel_buf,
		       sizeof(kernel_buf));

	debug("wmark_buf num=%d len=%d", kernel_buf.num, kernel_buf.len);

	return 0;
}

int process_import_get_msg(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	control_msg_t kernel_send;
	control_msg_list_t *_buf = NULL;

	debug();

	_buf = pop_msg(&dev->control_import_list_head.list); // 从 写 队列中拿 一个 free 的buf
	if (!_buf) {
		debug("pop_msg == NULL");
		return -EAGAIN;
	}
	memcpy(&kernel_send, &_buf->msg, sizeof(kernel_send));
	debug("pop_msg -- state=%d", kernel_send.state);

	kfree(_buf);

	copy_to_user((void __user *)argp, (void *)&kernel_send,
		     sizeof(kernel_send));

	return 0;
}

int process_export_get_msg(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	control_msg_t kernel_send;
	control_msg_list_t *_buf = NULL;

	debug();

	_buf = pop_msg(&dev->control_export_list_head.list); // 从 写 队列中拿 一个 free 的buf
	if (!_buf) {
		debug("pop_msg == NULL");
		return -EAGAIN;
	}
	memcpy(&kernel_send, &_buf->msg, sizeof(kernel_send));
	debug("pop_msg -- state=%d", kernel_send.state);

	kfree(_buf);

	copy_to_user((void __user *)argp, (void *)&kernel_send,
		     sizeof(kernel_send));

	return 0;
}

int process_get_msg(struct file *filp, void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	app_private_t *app = filp->private_data;
	int ret = 0;

	switch (app->type) {
		case APP_READ: // import app
		ret = process_import_get_msg(argp, dev);
		break;

		case APP_WRITE: // export app
		ret = process_export_get_msg(argp, dev);
		break;

		default:
		error("fail app type: %d\n", app->type);
		ret = -1;
		break;
	}
	return ret;
}

int process_import_set_msg(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	control_msg_t kernel_recv;
	int ret = 0;

	debug();

	copy_from_user((void *)&kernel_recv, (void __user *)argp,
		       sizeof(kernel_recv));

	if (get_import_s_m() != kernel_recv.state) {
		set_import_s_m(kernel_recv.state);
	} else {
		debug("repeat set state=%d", kernel_recv.state);
	}

	ret = send_msg_to_export(kernel_recv);

	return ret;
}

int process_export_set_msg(void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	control_msg_t kernel_recv;
	int ret = 0;

	debug();

	copy_from_user((void *)&kernel_recv, (void __user *)argp,
		       sizeof(kernel_recv));

	if (get_export_s_m() != kernel_recv.state) {
		set_export_s_m(kernel_recv.state);
	} else {
		debug("repeat set state=%d", kernel_recv.state);
	}

	ret = send_msg_to_import(kernel_recv);

	return ret;
}

int process_set_msg(struct file *filp, void __user *argp, wmark_dev_bufs_manager_t *dev)
{
	app_private_t *app = filp->private_data;
	int ret = 0;

	switch (app->type) {
		case APP_READ: // import app
		ret = process_import_set_msg(argp, dev);
		break;

		case APP_WRITE: // export app
		ret = process_export_set_msg(argp, dev);
		break;

		default:
		error("fail app type: %d\n", app->type);
		ret = -1;
		break;
	}
	return ret;
}


long wmark_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	wmark_dev_bufs_manager_t *dev = &global_bufs_manager;
	void __user *argp = (void __user *)arg;
	int ret = -1;
	debug("-> cmd=%ld", cmd);

	switch (cmd) {
	case SET_INIT_DMA_BUFS:
		debug("SET_INIT_DMA_BUFS ->");
		ret = export_init_dma_bufs(argp, dev);
		break;

	case GET_INIT_DMA_BUFS:
		debug("GET_INIT_DMA_BUFS ->");
		ret = import_init_dma_bufs(argp, dev);
		break;

	case SET_INIT_WMARK_BUFS:
		debug("SET_INIT_WMARK_BUFS ->");
		ret = export_init_wmark_bufs(argp, dev);
		break;

	case GET_INIT_WMARK_BUFS:
		debug("GET_INIT_WMARK_BUFS ->");
		ret = import_init_wmark_bufs(argp, dev);
		break;

	case SET_USE_BUF_INDEX_EXPORT: // 3
		debug("SET_USE_BUF_INDEX_EXPORT ->");
		ret = export_set_use_buf_index(argp, dev);
		break;

	case GET_FREE_BUF_INDEX_EXPORT: // 2
		debug("GET_FREE_BUF_INDEX_EXPORT ->");
		ret = export_get_free_buf_index(argp, dev);
		break;

	case SET_FREE_BUF_INDEX_IMPORT: // 1
		debug("SET_FREE_BUF_INDEX_IMPORT ->");
		ret = import_set_free_buf_index(argp, dev);
		break;

	case GET_USE_BUF_INDEX_IMPORT: // 4
		debug("GET_USE_BUF_INDEX_IMPORT ->");
		ret = import_get_use_buf_index(argp, dev);
		break;
	case GET_MSG_CTL:
		debug("GET_MSG_CTL ->");
		ret = process_get_msg(filp, argp, dev);
		break;
	case SET_MSG_CTL:
		debug("SET_MSG_CTL ->");
		ret = process_set_msg(filp, argp, dev);
		break;
	default:
		error("default ->");
		return -EINVAL;
		break;
	}
	return ret;
}

static unsigned int wmark_poll(struct file *filp, poll_table *wait)
{
	unsigned int mask = 0;
	wmark_dev_bufs_manager_t *dev = &global_bufs_manager;
	app_private_t *app = filp->private_data;


	mutex_lock(&dev->mutex);

	switch (app->type) {
		case APP_READ: // import app
		poll_wait(filp, &dev->import_msg_wait, wait);
		poll_wait(filp, &dev->r_wait, wait);

		// 如果 读 列表 非空， 代表 import 可以 获得 use (填充好有用数据) 的 buf.  可读
		if (!list_empty(&dev->wmark_r_list_head.list)) {
			mask |= POLLIN | POLLRDNORM;
		}

		if (!list_empty(&dev->control_import_list_head.list)) {
			mask |= POLLMSG;
		}
		break;

		case APP_WRITE: // export app
		poll_wait(filp, &dev->export_msg_wait, wait);
		poll_wait(filp, &dev->w_wait, wait);

		// 如果 写 列表 非空， 代表 exprot 可以 获得 free 的 buf.   可写
		if (!list_empty(&dev->wmark_w_list_head.list)) {
			mask |= POLLOUT | POLLWRNORM;
		}

		if (!list_empty(&dev->control_export_list_head.list)) {
			mask |= POLLMSG;
		}
		break;

		default:
		error("fail app type: %d\n", app->type);
		break;
	}

	mutex_unlock(&dev->mutex);
	return mask;
}

struct file_operations wmark_fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = wmark_ioctl,
	.compat_ioctl = wmark_ioctl,
	.open = wmark_open,
	.release = wmark_release,
	.poll = wmark_poll,
};

static struct miscdevice wmark_dev = {
	.fops = &wmark_fops,
	.minor = MISC_DYNAMIC_MINOR,
	.name = WMARK_DEV_NAME,
};

static int __init wmark_init(void)
{
	int ret = -1;
	debug();
	ret = misc_register(&wmark_dev);
	if (ret) {
		debug("fail misc wmark ion register.");
		goto fail;
	}

	memset(&global_bufs_manager, 0, sizeof(global_bufs_manager));
	INIT_LIST_HEAD(&global_bufs_manager.wmark_r_list_head.list);
	INIT_LIST_HEAD(&global_bufs_manager.wmark_w_list_head.list);
	mutex_init(&global_bufs_manager.mutex);
	init_waitqueue_head(&global_bufs_manager.r_wait); //初始化等待队列头
	init_waitqueue_head(&global_bufs_manager.w_wait);

	INIT_LIST_HEAD(&global_bufs_manager.control_export_list_head.list);
	INIT_LIST_HEAD(&global_bufs_manager.control_import_list_head.list);
	mutex_init(&global_bufs_manager.state_machine.state_m_mutex);
	mutex_init(&global_bufs_manager.control_export_list_head.mutex);
	mutex_init(&global_bufs_manager.control_import_list_head.mutex);
	init_waitqueue_head(&global_bufs_manager.export_msg_wait); //初始化等待队列头
	init_waitqueue_head(&global_bufs_manager.import_msg_wait); //初始化等待队列头

	return 0;
fail:
	return -ENOMEM;
}
module_init(wmark_init);

static void __exit wmark_exit(void)
{
	misc_deregister(&wmark_dev);
	debug();
}
module_exit(wmark_exit);

MODULE_AUTHOR("leo");
MODULE_LICENSE("Dual BSD/GPL");
